/**
 * ScreenshotParser 属性测试
 * 
 * 使用 fast-check 进行属性测试，验证截图解析器的正确性
 */

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as fc from 'fast-check';
import { ScreenshotParser } from './ScreenshotParser';
import { GitCodeApiService } from './GitCodeApiService';

// ============================================
// 生成器定义
// ============================================

/**
 * 生成有效的图片 MIME 类型
 */
const validMimeTypeArbitrary = fc.constantFrom(
  'image/png',
  'image/jpeg',
  'image/jpg',
  'image/gif',
  'image/webp'
);

/**
 * 生成无效的图片 MIME 类型
 */
const invalidMimeTypeArbitrary = fc.constantFrom(
  'text/plain',
  'application/pdf',
  'video/mp4',
  'audio/mp3',
  'application/json',
  ''
);

/**
 * 生成有效的文件大小（1字节到10MB）
 */
const validFileSizeArbitrary = fc.integer({ min: 1, max: 10 * 1024 * 1024 });

/**
 * 生成无效的文件大小（超过10MB）
 */
const invalidFileSizeArbitrary = fc.integer({ min: 10 * 1024 * 1024 + 1, max: 50 * 1024 * 1024 });

/**
 * 生成有效的发送者名称
 */
const senderArbitrary = fc.string({ minLength: 1, maxLength: 10 })
  .filter(s => {
    const trimmed = s.trim();
    return trimmed.length > 0 && 
           !trimmed.includes(':') && 
           !trimmed.includes('：') &&
           !trimmed.includes('\n');
  })
  .map(s => s.trim());

/**
 * 生成有效的消息内容
 */
const contentArbitrary = fc.string({ minLength: 1, maxLength: 50 })
  .filter(s => {
    const trimmed = s.trim();
    return trimmed.length > 0 && !trimmed.includes('\n');
  })
  .map(s => s.trim());

/**
 * 生成模拟的 OCR 识别结果（聊天格式）
 */
const ocrChatResultArbitrary = fc.array(
  fc.tuple(senderArbitrary, contentArbitrary),
  { minLength: 1, maxLength: 5 }
).map(messages => 
  messages.map(([sender, content]) => `${sender}: ${content}`).join('\n')
);

/**
 * 创建模拟的 File 对象
 */
function createMockFile(
  name: string,
  type: string,
  size: number
): File {
  // 创建指定大小的内容
  const content = new Uint8Array(Math.min(size, 100)); // 实际内容最多100字节
  const blob = new Blob([content], { type });
  
  // 创建 File 对象并覆盖 size 属性
  const file = new File([blob], name, { type });
  
  // 使用 Object.defineProperty 覆盖 size
  Object.defineProperty(file, 'size', {
    value: size,
    writable: false
  });
  
  return file;
}

// ============================================
// Property 10: 截图解析结果结构完整性
// ============================================

describe('ScreenshotParser Property Tests', () => {
  let parser: ScreenshotParser;
  let mockApiService: GitCodeApiService;

  beforeEach(() => {
    mockApiService = new GitCodeApiService({ apiKey: 'test-key' });
    parser = new ScreenshotParser(mockApiService);
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  /**
   * **Feature: smart-chat-reply, Property 10: 截图解析结果结构完整性**
   * **Validates: Requirements 6.1, 6.2**
   * 
   * 对于任意有效的图片文件，ScreenshotParser.parse() 应返回包含 
   * success、rawText、confidence 字段的结果对象，且不抛出异常
   */
  describe('Property 10: 截图解析结果结构完整性', () => {
    it('对于有效图片文件，应返回完整的结果结构且不抛出异常', async () => {
      await fc.assert(
        fc.asyncProperty(
          validMimeTypeArbitrary,
          validFileSizeArbitrary,
          ocrChatResultArbitrary,
          async (mimeType, fileSize, ocrResult) => {
            // 创建模拟文件
            const mockFile = createMockFile('test.png', mimeType, fileSize);
            
            // 模拟 API 响应
            vi.spyOn(mockApiService, 'analyzeImage').mockResolvedValue(ocrResult);
            
            // 执行解析，不应抛出异常
            let result;
            let thrownError: Error | null = null;
            try {
              result = await parser.parse(mockFile);
            } catch (e) {
              thrownError = e as Error;
            }
            
            // 验证不抛出异常
            expect(thrownError).toBeNull();
            
            // 验证结果结构完整性
            expect(result).toBeDefined();
            expect(typeof result!.success).toBe('boolean');
            expect(typeof result!.rawText).toBe('string');
            expect(typeof result!.confidence).toBe('number');
            expect(result!.confidence).toBeGreaterThanOrEqual(0);
            expect(result!.confidence).toBeLessThanOrEqual(1);
            expect(typeof result!.needsConfirmation).toBe('boolean');
            
            // parsedChat 可以是 null 或 ParsedChat 对象
            if (result!.parsedChat !== null) {
              expect(result!.parsedChat).toHaveProperty('messages');
              expect(result!.parsedChat).toHaveProperty('participants');
              expect(result!.parsedChat).toHaveProperty('emotionalTone');
            }
            
            // error 字段在失败时应存在
            if (!result!.success) {
              expect(result!.error).toBeDefined();
              expect(typeof result!.error).toBe('string');
            }
          }
        ),
        { numRuns: 100 }
      );
    });

    it('对于无效图片格式，应返回完整的错误结果结构', async () => {
      await fc.assert(
        fc.asyncProperty(
          invalidMimeTypeArbitrary,
          validFileSizeArbitrary,
          async (mimeType, fileSize) => {
            // 创建无效格式的文件
            const mockFile = createMockFile('test.txt', mimeType, fileSize);
            
            // 执行解析，不应抛出异常
            let result;
            let thrownError: Error | null = null;
            try {
              result = await parser.parse(mockFile);
            } catch (e) {
              thrownError = e as Error;
            }
            
            // 验证不抛出异常
            expect(thrownError).toBeNull();
            
            // 验证结果结构
            expect(result).toBeDefined();
            expect(result!.success).toBe(false);
            expect(typeof result!.rawText).toBe('string');
            expect(typeof result!.confidence).toBe('number');
            expect(result!.error).toBeDefined();
            expect(typeof result!.error).toBe('string');
          }
        ),
        { numRuns: 100 }
      );
    });

    it('对于超大文件，应返回完整的错误结果结构', async () => {
      await fc.assert(
        fc.asyncProperty(
          validMimeTypeArbitrary,
          invalidFileSizeArbitrary,
          async (mimeType, fileSize) => {
            // 创建超大文件
            const mockFile = createMockFile('large.png', mimeType, fileSize);
            
            // 执行解析，不应抛出异常
            let result;
            let thrownError: Error | null = null;
            try {
              result = await parser.parse(mockFile);
            } catch (e) {
              thrownError = e as Error;
            }
            
            // 验证不抛出异常
            expect(thrownError).toBeNull();
            
            // 验证结果结构
            expect(result).toBeDefined();
            expect(result!.success).toBe(false);
            expect(typeof result!.rawText).toBe('string');
            expect(typeof result!.confidence).toBe('number');
            expect(result!.error).toBeDefined();
            expect(result!.error).toContain('过大');
          }
        ),
        { numRuns: 100 }
      );
    });
  });

  // ============================================
  // Property 11: 低置信度识别需确认
  // ============================================

  /**
   * **Feature: smart-chat-reply, Property 11: 低置信度识别需确认**
   * **Validates: Requirements 6.4**
   * 
   * 对于任意 OCR 识别结果，如果 confidence 低于阈值（0.8），
   * 则 needsConfirmation 应为 true
   */
  describe('Property 11: 低置信度识别需确认', () => {
    it('低置信度结果应标记需要确认', async () => {
      // 测试低置信度场景：模糊图片
      const lowConfidenceOcrResults = [
        '张三: 你好\n[识别置信度: 低]',
        '模糊的文字内容',
        '不清晰的消息',
        '无法识别部分内容'
      ];

      for (const ocrResult of lowConfidenceOcrResults) {
        const mockFile = createMockFile('test.png', 'image/png', 1000);
        vi.spyOn(mockApiService, 'analyzeImage').mockResolvedValue(ocrResult);
        
        const result = await parser.parse(mockFile);
        
        // 如果置信度低于阈值，needsConfirmation 应为 true
        if (result.confidence < ScreenshotParser.getConfidenceThreshold()) {
          expect(result.needsConfirmation).toBe(true);
        }
      }
    });

    it('高置信度结果不需要确认', async () => {
      // 测试高置信度场景：清晰的聊天格式
      const highConfidenceOcrResult = '张三: 你好\n李四: 你好啊\n张三: 最近怎么样';
      
      const mockFile = createMockFile('test.png', 'image/png', 1000);
      vi.spyOn(mockApiService, 'analyzeImage').mockResolvedValue(highConfidenceOcrResult);
      
      const result = await parser.parse(mockFile);
      
      // 高置信度结果不需要确认
      if (result.confidence >= ScreenshotParser.getConfidenceThreshold()) {
        expect(result.needsConfirmation).toBe(false);
      }
    });

    it('置信度与 needsConfirmation 的关系应一致', async () => {
      await fc.assert(
        fc.asyncProperty(
          ocrChatResultArbitrary,
          fc.boolean(),
          async (ocrResult, addLowConfidenceMarker) => {
            // 根据标记决定是否添加低置信度标记
            const finalOcrResult = addLowConfidenceMarker 
              ? ocrResult + '\n[识别置信度: 低]'
              : ocrResult;
            
            const mockFile = createMockFile('test.png', 'image/png', 1000);
            vi.spyOn(mockApiService, 'analyzeImage').mockResolvedValue(finalOcrResult);
            
            const result = await parser.parse(mockFile);
            
            // 验证置信度与 needsConfirmation 的一致性
            const threshold = ScreenshotParser.getConfidenceThreshold();
            if (result.confidence < threshold) {
              expect(result.needsConfirmation).toBe(true);
            } else {
              expect(result.needsConfirmation).toBe(false);
            }
          }
        ),
        { numRuns: 100 }
      );
    });
  });

  // ============================================
  // 图片验证测试
  // ============================================

  describe('validateImage', () => {
    it('应正确验证有效的图片文件', () => {
      fc.assert(
        fc.property(
          validMimeTypeArbitrary,
          validFileSizeArbitrary,
          (mimeType, fileSize) => {
            const mockFile = createMockFile('test.png', mimeType, fileSize);
            const result = parser.validateImage(mockFile);
            expect(result.valid).toBe(true);
            expect(result.error).toBeUndefined();
          }
        ),
        { numRuns: 100 }
      );
    });

    it('应拒绝无效的图片格式', () => {
      fc.assert(
        fc.property(
          invalidMimeTypeArbitrary,
          validFileSizeArbitrary,
          (mimeType, fileSize) => {
            const mockFile = createMockFile('test.txt', mimeType, fileSize);
            const result = parser.validateImage(mockFile);
            expect(result.valid).toBe(false);
            expect(result.error).toBeDefined();
            expect(result.error).toContain('不支持的图片格式');
          }
        ),
        { numRuns: 100 }
      );
    });

    it('应拒绝超大文件', () => {
      fc.assert(
        fc.property(
          validMimeTypeArbitrary,
          invalidFileSizeArbitrary,
          (mimeType, fileSize) => {
            const mockFile = createMockFile('large.png', mimeType, fileSize);
            const result = parser.validateImage(mockFile);
            expect(result.valid).toBe(false);
            expect(result.error).toBeDefined();
            expect(result.error).toContain('过大');
          }
        ),
        { numRuns: 100 }
      );
    });
  });
});
